Dan je razred
def Uporabnik:
def init(ime, priimek):
self.ime = ime
self.priimek = priimek
def __str__(self)
print(ime + " " + priimek)
Popravi napake v definiciji razreda. Atributa naj ostaneta ime
in priimek
.
>>> jan = Uporabnik('Jan', 'Tisti')
>>> print(jan)
Jan Tisti
>>> jan.priimek
Tisti
>>> kitajc = Uporabnik('A', 'Li')
>>> print(kitajc)
A Li
>>> kitajc.ime
A
class Uporabnik: def __init__(self, ime, priimek): self.ime = ime self.priimek = priimek def __str__(self): return(self.ime + " " + self.priimek)
Spremeni konstruktor tako, da ne bo sprejemal imen in priimkov skupaj krajših od 5 črk.V tem primeru naj bo uporabnik Janez Slovenski.
>>> jan = Uporabnik('Jan', 'Tisti')
>>> print(jan)
Jan Tisti
>>> jan.priimek
Tisti
>>> kitajc = Uporabnik('A', 'Li')
>>> print(kitajc)
Janez Slovenski
>>> kitajc.ime
Janez
class Uporabnik: def __init__(self, ime, priimek): if len(ime+priimek) < 5: ime = 'Janez' priimek = 'Slovenski' self.ime = ime self.priimek = priimek def __str__(self): return(self.ime + " " + self.priimek)
Dodaj metodo inicialke, ki vrne inicialke uporabnika. Pri tem predpostavi, da ima vsak ime in priimek iz ene besede.
>>> jan = Uporabnik('Jan', 'Tisti')
>>> jan.inicialke()
J.T.
>>> legenda = Uporabnik('Bruce', 'Lee')
>>> legenda.inicialke()
B.L.
class Uporabnik: def __init__(self, ime, priimek): if len(ime+priimek) < 5: ime = 'Janez' priimek = 'Slovenski' self.ime = ime self.priimek = priimek def __str__(self): return(self.ime + " " + self.priimek) def inicialke(self): return self.ime[0] + '.' + self.priimek[0] + '.'
Ho Ši Minh se je pritožil in rekel, da so njegove inicialke H.Š.M. Podprla ga je tudi Ana Nina Vodičar Mehle, katere inicialke so po njenem A.N.V.M. . Peter Pavlovič Čehov pa je povedal, da se Ana Nina zmišljuje in da so njegove inicialke le P.Č. Da pa je bila zadeva še bolj zaostrena, se je v pogovor vmešal še Sebastian, ki pravi, da so njegove inicialke pač samo S.
Ker jim želiš vsem ustreči, dodaj še metodo polne_inicialke
tako, da bo imela parameter polno. Če bo nastavljen na True,
so inicialke sestavljene iz začetnic vseh besed, ki sestavljajo ime in priimek. Pri tem štejemo, da ime Ana Marija
sestavljata dve besedi, ime Ana-Nuša
pa le ena. Privzeta vrednost tega parametra pa je
False, kar pomeni, da se vzame le prva črka imena in prva črka priimka (razen za tako pomembne osebe, kot so Sebastian
ali pa Sting, ki so pač poznani le po imenu ali priimku - inicialke za oba sta S.
).
>>> jan = Uporabnik('Jan Jankovski', 'Tisti')
>>> jan.polne_inicialke(True)
J.J.T.
>>> jan = Uporabnik('Jan Jankovski', 'Tisti')
>>> jan.polne_inicialke()
J.T.
>>> jan = Uporabnik('Jan Jankovski', 'Tisti')
>>> jan.polne_inicialke(False)
J.T.
class Uporabnik: def __init__(self, ime, priimek): if len(ime + priimek) < 5: ime = 'Janez' priimek = 'Slovenski' self.ime = ime self.priimek = priimek def __str__(self): return (self.ime + " " + self.priimek) def polne_inicialke(self, polno = False): imena = self.ime.split() priimki = self.priimek.split() ini = '' for im in imena: ini += im[0] + '.' if not polno: break # le prvo for im in priimki: ini += im[0] + '.' if not polno: break # le prvo return ini
Trenutno je na spletu zelo popularna digitalna valuta
Bitcoin.
Osnova za pošteno uporabo take valute so zapleteni kriptografski
protokoli, mi pa bomo ubrali malo bolj poenostavljeno različico ter
sestavili razred BitniCekin
, s katerim bomo predstavili račun nekega
lastnika te valute.
POZOR:
Da ne bo težav pri testiranju, pri 2., 3. in 4. podnalogi začnemo z
class BitniCekini(BitniCekini):
To pomeni, da se v razred "skopirajo" vse definicije, ki ste jih v razred BitniCekini napisali prej. Seveda pa 1. podnalogo še vedno začnemo z
class BitniCekini():
Druga možnost pa je, da podanloge vedno začnemo z
class BitniCekini():
a potem v razred vedno napišemo vse metode, ki smo jih definirali v vseh prejšnjih podnalogah!
Sestavite razred BitniCekin
s konstruktorjem __init__(self, stanje)
,
ki sprejme začetno stanje na računu uporabnika (v valuti Bitcoin).
Atribut, v katerega shranite stanje, naj bo poimenovan _stanje
.
Argument stanje
naj bo neobvezen in v primeru, ko ni podan, naj bo
začetno stanje enako nič.
class BitniCekin: def __init__(self, stanje=0): self._stanje = stanje
Sestavite metodo __str__(self)
, ki predstavi stanje na računu v obliki:
'Število bitnih cekinov na računu: ...'
Primer:
>>> racun = BitniCekin(6)
>>> print(racun)
Število bitnih cekinov na računu: 6
class BitniCekin: def __init__(self, stanje=0): self._stanje = stanje def __str__(self): return 'Število bitnih cekinov na računu: {}'.format(self._stanje)
Sestavite metodi dvig(self, koliko)
in polog(self, koliko)
, ki
dvigneta oz. položita ustrezno količino bitnih cekinov na račun.
Predpostavimo, da bo vrednost argumenta koliko
vedno nenegativno
celo število.
Pri metodi dvig
upoštevajte, da stanje na računu ne sme biti negativno.
V takšnem primeru se dvig ne sme izvesti.
Metoda dvig
naj vrne True
, če je dvig uspel in False
, če ni.
Metoda polog
naj vrne stanje na računu po pologu.
class BitniCekin: def __init__(self, stanje=0): self._stanje = stanje def __str__(self): return 'Število bitnih cekinov na računu: {}'.format(self._stanje) def dvig(self, koliko): '''dvig sresdtev in potrditev uspešnosti transakcije''' if koliko > self._stanje: return False else: self._stanje -= koliko return True def polog(self, koliko): '''polog sredstev in vrednost trenutnega stanja''' self._stanje += koliko return self._stanje
Sestavite funkcijo prenesi(racun1, racun2, koliko)
, ki iz računa racun1
prenese koliko
cekinov na račun racun2
. Funkcija prenesi
naj ne bo
znotraj razreda BitniCekin
, saj ni objektna metoda, ampak je čisto običajna
funkcija. Spremenljivki racun1
in racun2
sta seveda objekta tipa BitniCekin
,
kar ni potrebno preverjati!
Če na računu racun1
ni dovolj denarja, se transakcija ne sme
izvršiti, torej mora stanje na obeh računih ostati nespremenjeno.
Funkcija naj vrne uspešnost transakcije (True
, če je transakcija uspela,
in False
, če ni).
def prenesi(racun1, racun2, koliko): '''prenos iz enega bitnega cekina na drugega in indikacija uspešnosti transakcije ''' if racun1.dvig(koliko): racun2.polog(koliko) return True return False
POZOR:
Da ne bo težav pri testiranju, pri 2., 3., 4. in 5. podnalogi začnemo z
class Datumi(Datumi):
To pomeni, da se v razred "skopirajo" vse definicije, ki ste jih v razred Datumi napisali prej. Seveda pa 1. podnalogo še vedno začnemo z
class Datumi():
Druga možnost pa je, da podanloge vedno začnemo z
class Datumi():
a potem v razred vedno napišemo vse metode, ki smo jih definirali v vseh prejšnjih podnalogah!
Definirajte razred Datum
, s katerim predstavimo datum. Najprej
sestavite konstruktor __init__(self, dan, mesec, leto)
. Atributi
razreda Datum
naj bodo poimenovani _dan
, _mesec
in _leto
.
>>> d = Datum(21, 5, 2013)
>>> d.leto
2013
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo __str__
, ki predstavi datum v berljivi obliki
'dan. mesec. leto'
.
>>> d = Datum(21, 5, 2013)
>>> print(d)
21. 5. 2013
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def __str__(self): return "{0}. {1}. {2}".format(self._dan, self._mesec, self._leto)
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo __lt__
, ki datum primerja z drugim datumom
(metoda naj vrne True
, če je prvi datum manjši, in False
, če ni).
Ko definirate to metodo, lahko datume primerjate kar z operatorjema
<
in >
. Na primer:
>>> Datum(31, 12, 1999) < Datum(1, 1, 2000)
True
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def __str__(self): return "{0}. {1}. {2}".format(self._dan, self._mesec, self._leto) def __lt__(self, other): # uporabimo Pythonovo vgrajeno leksikografsko primerjavo return (self._leto, self._mesec, self._dan) < (other._leto, other._mesec, other._dan)
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo __eq__
, ki datum primerja z drugim datumom
(metoda naj vrne True
, če sta datuma enaka, in False
, če nista).
Ko definirate to metodo, lahko datume primerjate kar z operatorjema
==
in !=
. Na primer:
>>> Datum(31, 12, 1999) != Datum(1, 1, 2000)
True
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def __eq__(self, other): # uporabimo Pythonovo vgrajeno leksikografsko primerjavo return (self._leto, self._mesec, self._dan) == (other._leto, other._mesec, other._dan)
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo iso8601
, ki vrne niz s predstavitvijo datuma oblike
yyyy-mm-dd
. Na prvem mestu je letnica, nato mesec in na koncu dan.
Števila so ločena z znaki '-'
. Letnica je štirimestno število, dan
in mesec pa dvomestni števili (po potrebi jih dopolnite z vodilnimi
ničlami.
>>> Datum(17, 3, 1999).iso8601()
'1999-03-17'
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def iso8601(self): return "{0:04}-{1:02}-{2:02}".format(self._leto, self._mesec, self._dan)
Definirajte razred Bakterija
, s katerim bomo predstavili bakterije.
Sestavite konstruktor, ki kot parameter sprejema niz, ki opisuje genski zapis bakterije in ta niz priredi atributu DNA
.
Preveriti pa morate, če je dani genski zapis veljaven, se pravi, da vsebuje samo črke 'A'
,'G'
,'C'
,'T'
(okrajšave za adenin, gvanin, citozin in timin). Če niz ni veljaven, naj atribut DNA
postane prazen niz.
Konstruktor mora narediti tudi atribut generacija
, ki naj dobi začetno vrednost 0
.
Primer:
>>> a = Bakterija('GAAATCGGT')
>>> a.DNA
'GAAATCGGT'
>>> a.generacija
0
Primer z neveljavnim genskim zapisom:
>>> a = Bakterija('ABCDEFGH')
>>> a.DNA
''
class Bakterija: def __init__(self, dna): self.DNA = dna if all([x in 'ACGT' for x in dna]) else '' self.generacija = 0 # če vam razumevanje zgornje kode dela težave - stvar bi lahko # napisali tudi # self.DNA = dna # # ali morda ni veljavno? # for znak in dna: # if znak not in 'ACGT': # self.DNA = '' # napačen znak, zato ... # break # self.generacija = 0
Bakterije se zelo rade delijo. Običajne bakterije delijo tako, da iz ene nastaneta dve novi, naše bakterije pa so posplošene bakterije, ki se lahko delijo na poljubno število novih bakterij. Pri tem se njihov genski zapis prekopira, poveča pa se števec generacije.
Definirajte metodo __floordiv__
, s katero je definirana operacija //
(celoštevilčno deljenje).
Metoda sprejema le en parameter (delitelj), ki pove, koliko bakterij dobimo po delitvi.
Metoda mora vrniti seznam novih bakterij, ki imajo isti DNA
kot začetna bakterija,
imajo pa povečan števec generacije.
Pri tem pa morate še upoštevati, da se bakterije s praznim genskim zapisom ne morejo deliti. V takšnem primeru
naj metoda vrne prazen seznam.
Primer:
>>> a = Bakterija('GAAATCGGT')
>>> nove_bakterije = a//3
>>> len(nove_bakterije)
3
>>> print(nove_bakterije)
[<__main__.Bakterija object at 0x7ffd41edac50>, <__main__.Bakterija object at 0x7ffd41edab90>, <__main__.Bakterija object at 0x7ffd41edab50>]
>>> nove_bakterije[0].generacija
1
>>> nove_bakterije[0].DNA
'GAAATCGGT'
class Bakterija(Bakterija): # zgornji zapis pomeni, da "poberemo" vse, kar smo do sedaj # že napisali v razredu Bakterija def __floordiv__(self, n): if not self.DNA: return [] nove = [] for i in range(n): b = Bakterija(self.DNA) b.generacija = self.generacija + 1 nove.append(b) return nove
Bakterije se lahko tudi združujejo. Pri tem nastane nova bakterija,
katere genski zapis je kombinacija genskih zapisov obeh bakterij, ki nastopata v združevanju.
Zapis se združuje po takšnem pravilu: izmenično se jemlje po eno črko iz
obeh genskih zapisov, ko pa pridemo do konca krajšega genskega zapisa, se preostanek daljšega
doda na konec novega zapisa.
Tako bi na primer pri združevanju zapisov ACT
in GCTATGCCC
dobili AGCCTTATGCCC
.
Definirajte metodo __add__
, s katero je definirana operacija +
(seštevanje).
To pomeni, da bomo bakterije lahko združevali kar z uporabo operatorja +
.
Metoda sprejema en parameter: drugo bakterijo, ki jo bomo združili s prvo.
Metoda naj vrne novo bakterijo, ki ima združen genski zapis ter za ena večji števec generacije kot
starejša od obeh bakterij, ki nastopata v združevanju.
Primer:
>>> a = Bakterija('ACT')
>>> b = Bakterija('GCTATGCCC')
>>> c = a + b
>>> c.DNA
'AGCCTTATGCCC'
>>> c.generacija
1
class Bakterija(Bakterija): # zgornji zapis pomeni, da "poberemo" vse, kar smo do sedaj # že napisali v razredu Bakterija def __add__(self, other): dna = '' ml = min(len(self.DNA), len(other.DNA)) for i in range(ml): dna += self.DNA[i] + other.DNA[i] dna += self.DNA[ml:] + other.DNA[ml:] nova = Bakterija(dna) nova.generacija = 1 + max(self.generacija, other.generacija) return nova
Bakterije lahko tudi mutirajo, pri čemer se jim spremeni genski zapis.
Na primer, podzaporedje AAG
se pri mutaciji spremeni v podzaporedje AAT
.
Pri mutaciji se vedno spremenijo vse pojavitve danega podzaporedja, če pa genski
zapis bakterije takšnega podzaporedja ne vsebuje, pa se med mutacijo DNA seveda ne spremeni.
Napišite metodo mutacija
, ki sprejme dva parametra, ki povesta,
v kaj se pri mutaciji spremeni dano podzaporedje genskega zapisa.
Metoda naj vrne novo bakterijo, ki ima mutiran genski zapis in za ena večji
števec generacije.
Upoštevajte, da se mutacije genskega zapisa vedno odvijajo v smeri od leve proti desni
(običajna smer v katero naraščajo indeksi).
Upoštevajte tudi, da bakterije brez genskega zapisa ne morejo mutirati. V takšnem
primeru naj metoda vrne isto, nespremenjeno bakterijo (nasvet: self
).
Nasvet: pomagajte si z metodo replace
!
Primer:
>>> a = Bakterija('GAAATCGGT')
>>> m = a.mutacija('AAT', 'CAT')
>>> m.DNA
'GACATCGGT'
>>> m.generacija
1
class Bakterija(Bakterija): # zgornji zapis pomeni, da "poberemo" vse, kar smo do sedaj # že napisali v razredu Bakterija def mutacija(self, fr, to): if not self.DNA: return self MDNA = self.DNA.replace(fr, to) nova = Bakterija(MDNA) nova.generacija = self.generacija + 1 return nova
Mnogokotnik v ravnini lahko predstavimo s seznamom njegovih oglišč (pari števil). Na primer seznam
[(0, 0), (1, 0), (1, 1), (0, 1)]
opisuje kvadrat, seznam
[(2, 0), (2, 1), (0, 2), (-2, 1), (-2, 0), (0, 1)]
pa opisuje (nekonveksen) šestkotnik.
Sestavite razred Mnogokotnik
, s katerim predstavimo ravninski
mnogokotnik. Najprej sestavite konstruktor __init__(self, ogl)
,
kjer je ogl
seznam njegovih oglišč. Atribut razreda naj bo
poimenovan oglisca
.
Nekateri ljudje mnogokotnike zapisujejo tako, da na konec seznama oglišč ponovno postavijo prvo oglišče (s tem poudarijo, da je mnogokotnik sklenjen). Zgornji kvadrat bi torej zapisali takole:
[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]
V našem razredu Mnogokotnik
naj se dolžina seznama oglisca
ujema s
številom oglišč mnogokotnika. Podvojeno oglišče na koncu seznama naj
konstruktor po potrebi odstrani. Zgled:
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
>>> p.oglisca
[(0, 0), (1, 0), (1, 1), (0, 1)]
Predpostavite lahko, da mnogokotniki ne bodo izrojeni (tj. če imata dve stranici neprazen presek, sta nujno sosednji, presek pa je natanko njuno skupno oglišče).
class Mnogokotnik(object): def __init__(self, oglisca): self.oglisca = list(oglisca) if self.oglisca[0] == self.oglisca[-1]: self.oglisca.pop()
V razredu Mnogokotnik
definirajte metodo obseg(self)
, ki izračuna in
vrne njegov obseg. Zgled:
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
>>> p.obseg()
4.0
def dolzina_daljice(a, b): ax, ay = a bx, by = b return ((ax - bx) ** 2 + (ay - by) ** 2) ** 0.5 class Mnogokotnik(Mnogokotnik): def obseg(self): ob = 0 n = len(self.oglisca) for i in range(n): ob += dolzina_daljice(self.oglisca[i], self.oglisca[(i + 1) % n]) return ob
V razredu Mnogokotnik
definirajte metodo ploscina(self)
, ki izračuna
in vrne njegovo ploščino.
Ploščina mnogokotnika (brez samopresečišč) z oglišči
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1)])
>>> p.ploscina()
1.0
class Mnogokotnik(Mnogokotnik): def ploscina(self): a = 0 n = len(self.oglisca) for i in range(n): x, y = self.oglisca[i] x2, y2 = self.oglisca[(i + 1) % n] a += x * y2 - x2 * y return abs(a) / 2
V razredu Mnogokotnik
definirajte metodo je_konveksen(self)
, ki
vrne True
, če je mnogokotnik konveksen in False
sicer.
Predstavljajte si, da je ravnina, na kateri leži mnogokotnik, vložena v
trirazsežni prostor tako, da je
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1)])
>>> p.je_konveksen()
True
>>> q = Mnogokotnik([(2, 0), (2, 1), (0, 2), (-2, 1), (-2, 0), (0, 1)])
>>> q.je_konveksen()
False
Predpostavite lahko, da nobeni dve zaporedni stranici ne oklepata iztegnjenega kota (180 °).
def vektorski_produkt(a, b): ax, ay, az = a bx, by, bz = b return (ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx) def smer_vrtenja(u, v, w): ux, uy = u vx, vy = v wx, wy = w z = vektorski_produkt((vx - ux, vy - uy, 0), (wx - vx, wy - vy, 0))[2] return 1 if z > 0 else -1 class Mnogokotnik(Mnogokotnik): def je_konveksen(self): n = len(self.oglisca) znak = smer_vrtenja(self.oglisca[0], self.oglisca[1], self.oglisca[2]) for i in range(1, n): u = self.oglisca[i % n] v = self.oglisca[(i + 1) % n] w = self.oglisca[(i + 2) % n] znak2 = smer_vrtenja(u, v, w) if znak2 * znak < 0: return False return True